import java.awt.*;
import java.awt.event.*;
import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

import javax.swing.*;

/**
 * Graphical user interface to a Tic Tac Toe application.
 * The GUI is incomplete because it has no associated player.
 * It also needs a routine for checking if one of the players
 * have got five marks in a row.
 */
public class TicTacToeGui extends JFrame implements Constants, ActionListener, TicTacToeRemote {
	/** Textfield showing what mark you use ('X' or 'O') */
	private JTextField id;
	/** TextArea giving feedback to the user */
	private TextArea display;
	/** The panel containing the board */
	private JPanel boardPanel;
	/** The squares of the board */
	private Square board[][];
	/** The menu bar */
	private JMenuBar menuBar;
	/** The game submenu */
	private JMenu gameMenu;
	/** Game submenu choices */
	private JMenuItem newGameItem, quitItem;
	
	/** The name of the player using this GUI */
	private String myName;
	/** The mark used by this player ('X' or 'O') */
	private char myMark;
	
	private boolean myTurn;
	private boolean gameOver = false;

	protected Service remoteBoard;
	
	public final static String ServiceName = "tictactoe";
	public final static int ServicePort = 1095;

	
	/**
	 * Creates a new GUI.
	 * @param name	The name of that player.
	 * @param mark	The mark used by that player.
	 */
	public TicTacToeGui(String name, char mark) {
		myName = name;
		myMark = mark;

		// Create GUI components:
		// The display at the bottom:
		display = new TextArea("", 4, 30, TextArea.SCROLLBARS_VERTICAL_ONLY);
		display.setEditable(false);
		// The name field at the top:
		id = new JTextField();
		id.setEditable(false);
		id.setText(myName + ": You are player " + myMark);
		// The board:
		JPanel gridPanel = new JPanel();
		gridPanel.setLayout(new GridLayout(BOARD_SIZE, BOARD_SIZE, 0, 0));
		board = new Square[BOARD_SIZE][BOARD_SIZE];
		for(int row = 0; row < board.length; row++) 
			for(int col = 0; col < board[row].length; col++) {
				board[row][col] = new Square(this, row, col);
				gridPanel.add(board[row][col]);
			}
		boardPanel = new JPanel();
		boardPanel.add(gridPanel);

		// Place the components:
		Container cp = getContentPane();
		cp.setLayout(new BorderLayout());
		cp.add("South", display);
		cp.add("North", id);
		cp.add("Center", boardPanel);

		// Create the menu.
		menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		gameMenu = new JMenu("Game");
		gameMenu.setMnemonic(KeyEvent.VK_G);
		menuBar.add(gameMenu);
		newGameItem = new JMenuItem("New game", KeyEvent.VK_N);
		newGameItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
		gameMenu.add(newGameItem);
		quitItem = new JMenuItem("Quit", KeyEvent.VK_Q);
		quitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, ActionEvent.ALT_MASK));
		gameMenu.add(quitItem);

		// Add listeners
		newGameItem.addActionListener(this);
		quitItem.addActionListener(this);
		// Add an anonymous WindowListener which calls quit() when the window is closing
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				quit();
			}
		});

		// Place and show the window:
		setTitle("Tic Tac Toe: " + name);
		setSize(WIN_WIDTH, WIN_HEIGHT);
		setLocation(200, 200);
		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		setVisible(true);
		
		Object[] options = {"Server",
        "Client"};
		int n = JOptionPane.showOptionDialog(this,
			    "Server/Client",
			    "Hey",
			    JOptionPane.YES_NO_CANCEL_OPTION,
			    JOptionPane.QUESTION_MESSAGE,
			    null,
			    options,
			    options[1]);
			//System.out.println("Valgte: " + n);
			if(n == 0){
				//Naive
				System.out.println("Server");
				myTurn = false;
				myMark = 'O';
				createTicTacToeServer();
			}else if(n == 1){
				//Smart
				System.out.println("Client");
				myTurn = true;
				String ip = JOptionPane.showInputDialog("Please input ip");
				if(ip != null && !ip.equals("")){
					connectToTicTacToeServer(ip);
				}
			}
			
		
	}
	
	public void guiMessage(String msg){
		display.append(msg + "\n");
	}

	public void connectToTicTacToeServer(String ip){
		 try
	      {
	    	  //78.91.11.18
	         System.out.println("Connecting...");
	         String serverObjectName = "rmi://" + ip + ":"
	            + NetworkModule.ServicePort + "/"
	            + NetworkModule.ServiceName;
	         remoteBoard = (Service)Naming.lookup(serverObjectName);
	         //
	         // the next two lines allow the server to call updateBoard:
	         //
	          UnicastRemoteObject.exportObject(this,0);
	          Service cserv = new NetworkModule(this);
	          remoteBoard.registerClient(cserv);
	          guiMessage("Connected to server");
	      }
	      catch ( Exception e )
	      {
	         System.out.println("Exception: " + e.getMessage());
	         e.printStackTrace();
	         return;
	      }
	}
	
	public void createTicTacToeServer(){
		try
		{
//			System.out.println("Creating server");
			LocateRegistry.createRegistry(1095);
//			System.out.println("Creating module");
			Service cserv = new NetworkModule(this);
//			System.out.println("Creating name");
			String serverObjectName = "rmi://localhost:" + ServicePort
					+ "/" + ServiceName;
//			System.out.println("Binding name");
			Naming.rebind(serverObjectName, cserv);
			System.out.println("Service is running.");
		}
		catch (Exception e)
		{
			System.out.println("Exception: " + e.getMessage());
			e.printStackTrace();
		}
	}
	
	public void setRemoteBoard(Service client){
		remoteBoard = client;
	}
	
	/**
	 * Called by the Square class when an empty square is clicked.
	 * @param row		The row of the square that was clicked.
	 * @param column	The column of the square that was clicked.
	 */
	public void squareClicked(int row, int column) {
		// This method must be modified!
		
		
		//gi beskjed til motspilleren om at spilleren har valgt denne posisjonen
		if(!myTurn || gameOver){
			return;
		}
		try {
			placeMark(row, column, myMark);
			setMark(row, column, myMark);
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		GameLogic gl = new GameLogic();
		if(gl.checkWinner(board)){
			guiMessage("You won!");
			try {
				remoteBoard.sendMsg("You lost");
				remoteBoard.gameOver();
				gameOver = true;
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	
	public void gameOver(){
		gameOver = true;
	}

	/**
	 * Marks the specified square of the board with the specified mark.
	 * @param row		The row of the square to mark.
	 * @param column	The column of the square to mark.
	 * @param mark		The mark to use.
	 */
	public void setMark(int row, int column, char mark) {
		board[row][column].setMark(mark);
		repaint();
	}

	/**
	 * Called when a menu item has been selected.
	 * @param e	The ActionEvent that occured.
	 */
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == newGameItem)
			newGame();
		else if(e.getSource() == quitItem)
			quit();
	}

	/**
	 * Starts a new game, if the user confirms it in a dialog box.
	 */
	public void newGame() {
		// This method must be modified!
		if(JOptionPane.showConfirmDialog(this, "Are you sure you want to start a new game?", "Start over?", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
			//gi beskjed til motspilleren om at et nytt spill skal startes
			try {
				remoteBoard.resetGame();
				remoteBoard.sendMsg("New game");
				guiMessage("New game");
				clearBoard();
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/**
	 * Removes all marks from the board.
	 */
	public void clearBoard() {
		for(int row = 0; row < board.length; row++)
			for(int col = 0; col < board[row].length; col++)
				board[row][col].setMark(' ');
		repaint();
		gameOver = false;
	}

	/**
	 * Exits the game, if the user confirms it in a dialog box.
	 * Should notify the opponent that we left the game.
	 */
	public void quit() {
		// This method should be modified!
		if(JOptionPane.showConfirmDialog(this, "Are you sure you want to quit?", "Really quit?", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
			System.exit(0);
			
			//gi beskjed til motspilleren om at spillet er ferdig.
		}
	}

	/**
	 * Outputs a message to the user.
	 * @param s	The string to display. Adds a newline to the end of the string.
	 */
	public void println(String s) {
		display.append(s + "\n");
	}

	/**
	 * Outputs a message to the user.
	 * @param s	The string to display.
	 */
	public void print(String s) {
		display.append(s);
	}

	/**
	 * Starts up a GUI without an associated player, in order
	 * to check the appearance of the GUI.
	 */
	public static void main(String args[]) {
			
		TicTacToeGui hisGui = new TicTacToeGui("Knut", 'X');
	}

	@Override
	public boolean placeMark(int row, int col, char mark)
			throws RemoteException {
		// TODO Auto-generated method stub
		myTurn = false;
		remoteBoard.placeMark(row, col, mark);			
		return false;
	}
	
	public void setMyTurn(){
		myTurn = true;
	}
}
